/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package pos.controller;

import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.logging.Level;
import java.util.logging.Logger;
import pos.client.dac.dao.*;
import pos.client.dac.dcs.*;
import pos.domain.*;
import pos.dto.StudenteDTO;
import pos.gui.Index;
import pos.server.dac.exceptions.EccezioneCRUD;

/**
 *
 * @author Alessio
 */
public class UtenteController
{
    private static class CorsoCallback implements AsyncCallback<Void>
    {
        private boolean hasNext;
        private Utente u;

        public CorsoCallback(boolean hasNext, Utente u)
        {
            this.hasNext = hasNext;
            this.u = u;
        }

        @Override
        public void onFailure(Throwable caught)
        {
            throw new UnsupportedOperationException("Not supported yet.");
        }

        @Override
        public void onSuccess(Void result)
        {
            if (hasNext) {
                view.logged(u);
                System.out.println("Logged nuovo utente");
            }
        }
    }

    private static class CorsoRepositoryCallback implements AsyncCallback<Collection<Corso>>
    {
        private Piano p;
        private Utente u;

        public CorsoRepositoryCallback(Piano piano, Utente u)
        {
            p = piano;
            this.u = u;
        }

        @Override
        public void onFailure(Throwable caught)
        {
            throw new UnsupportedOperationException("Not supported yet.");
        }

        @Override
        public void onSuccess(Collection<Corso> result)
        {
            System.out.println("In onSuccess CorsoRepositoryCallback");
            for (Corso c : result) {
                TipoLinkcomposto_da link = null;
                try {
                    link = new TipoLinkcomposto_da(p, c, 0, 0);
                } catch (EccezionePrecondizioni ex) {
                    Logger.getLogger(UtenteController.class.getName()).log(Level.SEVERE, null, ex);
                }
                linkComposto_daService.leggiDatidaDb(link, u, new AsyncCallback<TipoLinkcomposto_da>()
                {
                    @Override
                    public void onFailure(Throwable caught)
                    {
                        throw new UnsupportedOperationException("Not supported yet.");
                    }

                    @Override
                    public void onSuccess(TipoLinkcomposto_da result)
                    {
                        p.inserisciCorso(result);

                        System.out.println("Logged carica: Corso - " + result.getCorso());
                        view.logged(u);
                    }
                });
            }
        }
    }

    private UtenteController()
    {
    }
    private static Index view;
    private static UniversitaServiceAsync service = (UniversitaServiceAsync) GWT.create(UniversitaService.class);
    private static CorsoDCSAsync dcs = (CorsoDCSAsync) GWT.create(CorsoDCS.class);
    private static CorsoDAOAsync corsoService = (CorsoDAOAsync) GWT.create(CorsoDAO.class);
    private static PianoDAOAsync pianoService = (PianoDAOAsync) GWT.create(PianoDAO.class);
    private static UtenteDAOAsync utenteService = (UtenteDAOAsync) GWT.create(UtenteDAO.class);
    private static PianoDCSAsync pianoRepository = (PianoDCSAsync) GWT.create(PianoDCS.class);
    private static CorsoDCSAsync corsoRepository = (CorsoDCSAsync) GWT.create(CorsoDCS.class);
    private static TipoLinkcomposto_daDAOAsync linkComposto_daService = (TipoLinkcomposto_daDAOAsync) GWT.create(TipoLinkcomposto_daDAO.class);

    public static void login(final String login, final String password)
    {
        //carichi studenteDTO;
        System.out.println("In metodo login");
        service.getStudenteByLogin(login, new AsyncCallback<StudenteDTO>()
        {
            @Override
            public void onSuccess(StudenteDTO result)
            {

                final StudenteDTO dto = result;
                //guardiaPasswordNull

                if (result == null || result.password == null) {
                    Window.alert("Matricola non trovata");
                    System.out.println("Matricola non trovata");
                    return;
                }

                //guardiaPasswordErrata
                if (!result.password.equals(password)) {
                    Window.alert("Password errata");
                    return;
                }
                //guardiaPianodistudio
                if (!result.is_piano_di_studio_compilato) {
                    Window.alert("Prima di utilizzare l'organizzatore devi compilare il piano di studi presso l'universita");
                    return;
                }
                //caricamentoUtenteDaOrganizzatore
                final Utente u = new Utente(login, null, 0);
                utenteService.leggiDatidaDB(u, new AsyncCallback<Utente>()
                {
                    @Override
                    public void onSuccess(Utente result)
                    {

                        //utente in organizzatore ?
                        if (result.getPassword() != null) {
                            System.out.println("Utente esistente (fa pure rima!)");
                            //SI
                            //modificato piano di studi?
                            if (result.getUltimaModifica() != dto.ultima_modifica)
                            {
                                //SI sincronizzazione corsi
                                u.setPassword(dto.password);
                                u.setUltimaModifica(dto.ultima_modifica);
                                sincronizza(u);
                            }
                            else
                                //NO caricamento corsi
                                carica(u);
                        }//NO
                        else
                            // creazioneUtente
                            creaUtente(u);
                    };

                    @Override
                    public void onFailure(Throwable caught)
                    {
                        Window.alert(caught.getMessage());
                    }
                });
            }

            @Override
            public void onFailure(Throwable caught)
            {
                Window.alert("Impossibile contattare il server.");
                Window.alert(caught.getMessage());
            }
        });


    }

    private static void sincronizza(final Utente u)
    {

        try {
            dcs.findByUtente(u, new AsyncCallback<Collection<Corso>>()
            {
                @Override
                public void onSuccess(Collection<Corso> result)
                {
                    final Collection<Corso> corsiVecchi = result;
                    service.findCorsiByUtente(u.getLogin(), new AsyncCallback<Collection<Corso>>()
                    {
                        @Override
                        public void onSuccess(Collection<Corso> result)
                        {
                            final Collection<Corso> corsiPianoDiStudio = result;

                            Collection<Corso> nuovi;
                            Collection<Corso> eliminati;

                            nuovi = new HashSet<Corso>();
                            nuovi.addAll(corsiPianoDiStudio);
                            nuovi.removeAll(corsiVecchi);

                            eliminati = new HashSet<Corso>();
                            eliminati.addAll(corsiVecchi);
                            eliminati.removeAll(corsiPianoDiStudio);
                            
                            AsyncCallback<Void> dummy = new AsyncCallback<Void>() {

                                @Override
                                public void onFailure(Throwable caught)
                                {
                                    System.out.println(caught);
                                }

                                @Override
                                public void onSuccess(Void result)
                                {
                                }
                            };
                            for (Corso c : eliminati)
                                corsoService.cancellaDatidaDB(c, u, dummy);

                            for (Corso c : nuovi)
                                corsoService.inserisciDatisuDB(c, u, dummy);

                            for (Corso c : corsiPianoDiStudio)
                                try {
                                    u.inserisciLinkDeveSostenere(new TipoLinkDeveSostenere(u, c));
                                } catch (EccezionePrecondizioni ex) {
                                    Logger.getLogger(UtenteController.class.getName()).log(Level.SEVERE, null, ex);
                                }
                            utenteService.aggiornaDatisuDB(u, dummy);
                            carica(u);
                            System.out.println("Sincronizzato");
                        }

                        @Override
                        public void onFailure(Throwable caught)
                        {
                            throw new UnsupportedOperationException("Not supported yet.");
                        }
                    });
                }

                @Override
                public void onFailure(Throwable caught)
                {
                    throw new UnsupportedOperationException("Not supported yet.");
                }
            });
        } catch (EccezioneCRUD ex) {
            Window.alert("Errore nella comunicazione con il server");
        }
    }

    private static void carica(final Utente u)
    {
        try {
            pianoRepository.findByUtente(u, new AsyncCallback<Collection<Piano>>()
            {
                @Override
                public void onFailure(Throwable caught)
                {
                    throw new UnsupportedOperationException("Not supported yet.");
                }

                @Override
                public void onSuccess(Collection<Piano> result)
                {
                    for (Piano p : result)
                        try {
                            u.inserisciLinkCrea(new TipoLinkU_P(u, p));
                        } catch (EccezionePrecondizioni ex) {
                            Logger.getLogger(UtenteController.class.getName()).log(Level.SEVERE, null, ex);
                        }
                    service.findCorsiByUtente(u.getLogin(), new AsyncCallback<Collection<Corso>>()
                    {
                        @Override
                        public void onSuccess(Collection<Corso> result)
                        {
                            final Collection<Corso> corsiPianoDiStudio = result;

                            for (Corso c : corsiPianoDiStudio)
                                try {
                                    u.inserisciLinkDeveSostenere(new TipoLinkDeveSostenere(u, c));
                                } catch (EccezionePrecondizioni ex) {
                                    Logger.getLogger(UtenteController.class.getName()).log(Level.SEVERE, null, ex);
                                }
                            for (Iterator<TipoLinkU_P> it = u.getLinkCrea().iterator(); it.hasNext();) {
                                TipoLinkU_P linkU_P = it.next();
                                try {
                                    corsoRepository.findByPiano(linkU_P.getPiano(), new CorsoRepositoryCallback(linkU_P.getPiano(), u));

                                    System.out.println("canContinue: " + !it.hasNext());
                                } catch (EccezioneCRUD ex) {
                                    Logger.getLogger(UtenteController.class.getName()).log(Level.SEVERE, null, ex);
                                }
                            }


                        }

                        @Override
                        public void onFailure(Throwable caught)
                        {
                            throw new UnsupportedOperationException("Not supported yet.");
                        }
                    });
                }
            });
        } catch (EccezioneCRUD ex) {
            Logger.getLogger(UtenteController.class.getName()).log(Level.SEVERE, null, ex);
        }

    }

    private static void creaUtente(Utente u)
    {
        service.getStudenteByLogin(u.getLogin(), new AsyncCallback<StudenteDTO>()
        {
            @Override
            public void onSuccess(final StudenteDTO dto)
            {
                final Utente u = new Utente(dto.matricola, dto.password, dto.ultima_modifica);
                utenteService.inserisciDatisuDB(u, new AsyncCallback<Void>()
                {
                    @Override
                    public void onFailure(Throwable caught)
                    {
                        caught.printStackTrace();
                        StackTraceElement[] stackTrace = caught.getStackTrace();
                    }

                    @Override
                    public void onSuccess(Void result)
                    {
                        Piano p =  new Piano("Piano 1");

                        pianoService.inserisciDatisuDB(p, u, new AsyncCallback<Piano>()
                        {
                            @Override
                            public void onFailure(Throwable caught)
                            {
                            }

                            @Override
                            public void onSuccess(Piano result)
                            {
                                try {
                                    result.inserisciLinkCrea(new TipoLinkU_P(u, result));
                                } catch (EccezionePrecondizioni ex) {
                                    System.out.println(ex.toString());
                                }
                                service.findCorsiByUtente(dto.matricola, new AsyncCallback<Collection<Corso>>()
                                {
                                    @Override
                                    public void onSuccess(Collection<Corso> result)
                                    {
                                        final Iterator<Corso> it;
                                        for (it = result.iterator(); it.hasNext();) {

                                            final Corso c = it.next();
                                            try {
                                                u.inserisciLinkDeveSostenere(new TipoLinkDeveSostenere(u, c));
                                            } catch (EccezionePrecondizioni ex) {
                                                Logger.getLogger(UtenteController.class.getName()).log(Level.SEVERE, null, ex);
                                            }

                                            corsoService.inserisciDatisuDB(c, u, new CorsoCallback(it.hasNext(), u));
                                        }
                                    }

                                    @Override
                                    public void onFailure(Throwable caught)
                                    {
                                        throw new UnsupportedOperationException("Not supported yet.");
                                    }
                                });
                            }
                        });
                    }
                });
            }

            @Override
            public void onFailure(Throwable caught)
            {
                Window.alert(caught.toString());
            }
        });
    }

    /**
     * @return the view
     */
    public static Index getView()
    {
        return view;
    }

    /**
     * @param aView the view to set
     */
    public static void setView(Index aView)
    {
        view = aView;
    }
}
